﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AlgorithmResult;
using System.Diagnostics;
using SimilarityToAncientCodon;

namespace CodonSegDP
{

  


	public class DPAlg
	{
       
        private int codonSize = 3;
        public Boolean NeedToStop {get;set;}
      
        public event ProgressEventHandler ProgressHandler = null;
        public String Text = String.Empty;
        int minSegmentSize = 2;
        Segment leftSegment;
        public Segment LeftSegment
        {
            get
            {
                return leftSegment;
            }
            set
            {
                if (leftSegment == value)
                    return;
                leftSegment = value;
            }
        }
        Segment rightSegment;
        public Segment RightSegment
        {
            get
            {
                return rightSegment;
            }
            set
            {
                if (rightSegment == value)
                    return;
                rightSegment = value;
            }
        }
        int[] rangeCodon ;
        public DPAlg(String _Text, int _minSegmentSize, int[] _rangeCodon)
        {
            //codonSize = _codonSize;
            Text = _Text;
            minSegmentSize = _minSegmentSize;
            rangeCodon = _rangeCodon;
            codonSize = _rangeCodon[0];
            NeedToStop = false;
        }
        

        public Result TripletBounderiesSegmentator()
        {
            int curPostion = 0;


            double[] costSegment = new double[Text.Length];
            String[] tmpArchreTriplets = new String[Text.Length];
            int i = 0;
            long[] BoundariesSet = new long[Text.Length / minSegmentSize - 1];
            String[] ArchreTriplets = new String[Text.Length / minSegmentSize - 1];

            int boundery_index = 0;
            
            int lastBoundaryValueIndex = 0;

            int maxCostSegment = 0;
            int numOftripletsforLeftSide = minSegmentSize;
            int numOftripletsforRightSide = minSegmentSize;
            int windowSize = (minSegmentSize * 2) * rangeCodon[rangeCodon.Length-1];
            Dictionary<int, BoudarySearcher> dict = new Dictionary<int, BoudarySearcher>();
            for (i = 0; i < rangeCodon.Length; ++i)
            {
                dict[rangeCodon[i]] = new BoudarySearcher(Text, minSegmentSize, rangeCodon[i]); 
            }

                while (curPostion != Text.Length && (curPostion + windowSize) < Text.Length && !NeedToStop)
                {

                    for (i = 0; i < rangeCodon.Length; ++i)
                    {
                        dict[rangeCodon[i]].SearchBoundary(curPostion);
                    }
                  int searcheIndx=  FindMaxCostSegmentFromDifferentCodonSize(dict);
                        // founded max cost segment value === > found new real boundary

                  curPostion = dict[rangeCodon[searcheIndx]].GetPositionAfterFoundedMaxCostSegment();// dict[costSegment[maxCostSegment]];
                    lastBoundaryValueIndex = curPostion;
                    ArchreTriplets[boundery_index] = dict[rangeCodon[searcheIndx]].GetArcheTripletAfterFoundedMaxCostSegment(); // tmpArchreTriplets[maxCostSegment];
                    if ((boundery_index > 0 && ArchreTriplets[boundery_index - 1] == ArchreTriplets[boundery_index]) == false)
                    {

                        BoundariesSet[boundery_index++] = curPostion;
                        if (ProgressHandler != null)
                        {

                            ProgressHandler(this, new progressEvent(curPostion, null));
                        }
                        if (curPostion == 744)
                        {
                            curPostion = curPostion;
                        }
                    }
                    else
                    {
                        ArchreTriplets[boundery_index] = String.Empty;
                        BoundariesSet[boundery_index - 1] = curPostion;
                    }


                    


                }


                leftSegment = new Segment(Text, codonSize, minSegmentSize);
            while (curPostion + codonSize <= Text.Length)
            {
                leftSegment.AddTripletToSegment(Text.Substring(curPostion, codonSize));
                curPostion += codonSize;


            }
            String ArcheTriplet = String.Empty;
            leftSegment.EvaluateCostFunction();
            ArcheTriplet = leftSegment.ArcheCodonName;
            if (ArcheTriplet == ArchreTriplets[boundery_index - 1])
            {
                BoundariesSet[boundery_index - 1] = curPostion;
            }
            else
            {
                BoundariesSet[boundery_index] = curPostion;
                ArchreTriplets[boundery_index] = ArcheTriplet;
                boundery_index++;

            }

            Result bestResultOfSegGen = new Result(BoundariesSet, ArchreTriplets, boundery_index);
            FragmentSimToAncientCodon simToAncientCodon = new FragmentSimToAncientCodon(bestResultOfSegGen, Text);

            return bestResultOfSegGen;
        }

        private int FindMaxCostSegmentFromDifferentCodonSize(Dictionary<int, BoudarySearcher> dict)
        {
         
            int max_cost_index = 0;
            Random m_rand = new Random((int)DateTime.Now.Ticks);
            for (int i = 0; i < rangeCodon.Length; ++i)
            {

                if (dict[rangeCodon[i]].costSegment[dict[rangeCodon[i]].maxCostSegment] > dict[rangeCodon[max_cost_index]].costSegment[dict[rangeCodon[max_cost_index]].maxCostSegment])
                {
                    max_cost_index = i;
                }
                else if (dict[rangeCodon[i]].costSegment[dict[rangeCodon[i]].maxCostSegment] == dict[rangeCodon[max_cost_index]].costSegment[dict[rangeCodon[max_cost_index]].maxCostSegment])
                {
                    if (m_rand.Next(2) == 0)
                    {
                        max_cost_index = i;
                    }
                }
            }
            return max_cost_index;
        }


        


        private void ZeroArcheTripletsStrings(string[] tmpArchreTriplets, ref int costSegmentIndx)
        {
            for (int i = 0; i < costSegmentIndx; i++)
            {
                tmpArchreTriplets[i] = String.Empty ;
            }
        }

        private long FindLastBoundaryIndx(long[] BoundariesSet)

        {
            long index = BoundariesSet.LastOrDefault<long>(num => num > 0);
       //     for(int i=0;i<BoundariesSet.Length)
            return index;
        }

   

        private void ZeroCosegment(double[] costSegment, ref int costSegmentIndx)
        {
            for (int i = 0; i < costSegmentIndx; i++)
            {
                costSegment[i] = 0;
            }
           
        }


        private int FindMaxCostSegment(double[] costsegment, ref int costSegmentIndx)
        {
            int max_cost_index=0;
            double max_value = 0;

            for (int i = 0; i < costSegmentIndx; ++i)
            {
                if (costsegment[i] >= costsegment[max_cost_index])
                {
                    max_cost_index = i;
                }
            }
            return max_cost_index;
 
        }
        



	}
}
